package com.breadenglish.cms.api.app.gateway.componet;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by 坤 on 2015/3/11.
 * 暂时使用自定义错误处理，spring boot已配置error处理，json版本的客户端必须用application/json请求
 */
//@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {

    @ResponseStatus(value = HttpStatus.UNPROCESSABLE_ENTITY)
    @ExceptionHandler({InvalidRequestException.class})
    protected ResponseEntity<Object> handleInvalidRequest(RuntimeException e, WebRequest request, HttpServletRequest response) {
        InvalidRequestException ire = (InvalidRequestException) e;
        List<FieldErrorResource> fieldErrorResources = new ArrayList<FieldErrorResource>();

        List<FieldError> fieldErrors = ire.getErrors().getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
            FieldErrorResource fieldErrorResource = new FieldErrorResource();
            fieldErrorResource.setResource(fieldError.getObjectName());
            fieldErrorResource.setField(fieldError.getField());
            fieldErrorResource.setCode(fieldError.getCode());
            fieldErrorResource.setMessage(fieldError.getDefaultMessage());
            fieldErrorResources.add(fieldErrorResource);
        }

        ErrorResource error = new ErrorResource("InvalidRequest", ire.getMessage());
        error.setFieldErrors(fieldErrorResources);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        return handleExceptionInternal(e, error, headers, HttpStatus.UNPROCESSABLE_ENTITY, request);
    }
//    @ResponseStatus(value = HttpStatus.UNPROCESSABLE_ENTITY)
//    @ExceptionHandler({InvalidRequestException.class})
//    protected String handleInvalidRequestJson(RuntimeException e, WebRequest request) throws JsonProcessingException {
//        return MyExceptionHandler.getJsonError((InvalidRequestException) e);
//    }

    public static ErrorResource getErrorResourceFromException(InvalidRequestException ire) {
        List<FieldErrorResource> fieldErrorResources = new ArrayList<FieldErrorResource>();

        List<FieldError> fieldErrors = ire.getErrors().getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
            FieldErrorResource fieldErrorResource = new FieldErrorResource();
            fieldErrorResource.setResource(fieldError.getObjectName());
            fieldErrorResource.setField(fieldError.getField());
            fieldErrorResource.setCode(fieldError.getCode());
            fieldErrorResource.setMessage(fieldError.getDefaultMessage());
            fieldErrorResources.add(fieldErrorResource);
        }
        ErrorResource error = new ErrorResource("InvalidRequest", ire.getMessage());
        error.setFieldErrors(fieldErrorResources);
        return error;
    }

    public static ErrorResource getErrorResourceFromException(ConstraintViolationException e) {
        List<FieldErrorResource> fieldErrorResources = new ArrayList<FieldErrorResource>();
        for (ConstraintViolation fieldError : e.getConstraintViolations()) {
            FieldErrorResource fieldErrorResource = new FieldErrorResource();
            fieldErrorResource.setResource(fieldError.getRootBeanClass().getName());
            fieldErrorResource.setField(fieldError.getPropertyPath().toString());
            fieldErrorResource.setCode(fieldError.getMessage());
            fieldErrorResource.setMessage(fieldError.getMessage());
            fieldErrorResources.add(fieldErrorResource);
        }
        ErrorResource error = new ErrorResource("InvalidRequest", e.getMessage());
        error.setFieldErrors(fieldErrorResources);
        return error;
    }

    static ObjectMapper objectMapper = new ObjectMapper();

    public static String getJsonError(InvalidRequestException e) throws JsonProcessingException {
        return objectMapper.writeValueAsString(getErrorResourceFromException(e));
    }

    public static String getJsonError(ConstraintViolationException e) throws JsonProcessingException {
        return objectMapper.writeValueAsString(getErrorResourceFromException(e));
    }

    public static boolean InvalidRequestExceptionHandler(BindingResult result) {
        if (result.hasErrors()) {
            throw new InvalidRequestException("Invalid parameter", result);
        }
        return true;
    }
}